package category

import (
	"context"
	"encoding/json"
	"net/http"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"google.golang.org/protobuf/types/known/emptypb"

	"mxshop-api/goods-web/api"
	categoryForm "mxshop-api/goods-web/forms/category"
	"mxshop-api/goods-web/global"
	proto "mxshop-api/goods-web/proto/gen/v1"
)

func List(c *gin.Context) {
	resp, err := proto.NewGoodsClient(global.Conn).GetAllCategoryList(context.Background(), &emptypb.Empty{})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	categories := make([]interface{}, 0, resp.Total)
	err = json.Unmarshal([]byte(resp.JsonData), &categories)
	if err != nil {
		zap.L().Error("json unmarshal failed", zap.Error(err))
	}
	c.JSON(http.StatusOK, categories)
}

func Detail(c *gin.Context) {
	var categoryIns categoryForm.Category
	err := c.ShouldBindUri(&categoryIns)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	resp, err := proto.NewGoodsClient(global.Conn).GetSubCategory(context.Background(), &proto.CategoryListRequest{
		Id: categoryIns.ID,
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	reMap := make(map[string]interface{}, 6)
	subCategories := make([]map[string]interface{}, 0, len(resp.SubCategory))
	for _, value := range resp.SubCategory {
		subCategories = append(subCategories, map[string]interface{}{
			"id":              value.Id,
			"name":            value.Name,
			"level":           value.Level,
			"parent_category": value.ParentCategory,
			"is_tab":          value.IsTab,
		})
	}
	reMap["id"] = resp.Info.Id
	reMap["name"] = resp.Info.Name
	reMap["level"] = resp.Info.Level
	reMap["parent_category"] = resp.Info.ParentCategory
	reMap["is_tab"] = resp.Info.IsTab
	reMap["sub_categories"] = subCategories

	c.JSON(http.StatusOK, reMap)
}

func New(c *gin.Context) {
	var form categoryForm.Form
	err := c.ShouldBind(&form)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}
	if form.ParentCategory == 0 && form.Level > 1 {
		c.JSON(http.StatusBadRequest, gin.H{
			"error": "parent_category must be greater than 0 if level greater than 1",
		})
		return
	}

	ctx := context.Background()
	goodsCli := proto.NewGoodsClient(global.Conn)
	resp, err := goodsCli.CreateCategory(ctx, &proto.CategoryInfoRequest{
		Name:           form.Name,
		ParentCategory: form.ParentCategory,
		Level:          form.Level,
		IsTab:          form.IsTab,
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	categoryResp, err := goodsCli.GetSubCategory(ctx, &proto.CategoryListRequest{
		Id: resp.Id,
	})

	rtnMap := make(map[string]interface{}, 5)
	rtnMap["id"] = categoryResp.Info.Id
	rtnMap["name"] = categoryResp.Info.Name
	rtnMap["level"] = categoryResp.Info.Level
	rtnMap["is_tab"] = categoryResp.Info.IsTab
	if categoryResp.Info.ParentCategory > 0 {
		rtnMap["parent"] = categoryResp.Info.ParentCategory
	}

	c.JSON(http.StatusCreated, rtnMap)
}

func Update(c *gin.Context) {
	var categoryIns categoryForm.Category
	var updateForm categoryForm.UpdateForm
	err := c.ShouldBindUri(&categoryIns)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}
	err = c.ShouldBind(&updateForm)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	// 1.因为业务关系:关联的关系已经是全部绑定的不允许修改,因此只允许更改: 分类名称、是否在表格中展示。
	req := proto.CategoryInfoRequest{
		Id:   categoryIns.ID,
		Name: updateForm.Name,
	}
	if updateForm.IsTab != nil {
		req.IsTab = *updateForm.IsTab
	}

	_, err = proto.NewGoodsClient(global.Conn).UpdateCategory(context.Background(), &req)
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	c.Status(http.StatusCreated)
}

func Delete(c *gin.Context) {
	var categoryIns categoryForm.Category
	err := c.ShouldBindUri(&categoryIns)
	if err != nil {
		api.HandleValidatorError(c, err)
		return
	}

	// 1. 先查询出该分类写的所有子分类
	// 2. 将所有的分类全部逻辑删除
	// 3. 将该分类下的所有的商品逻辑删除
	_, err = proto.NewGoodsClient(global.Conn).DeleteCategory(context.Background(),
		&proto.DeleteCategoryRequest{Id: categoryIns.ID},
	)
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	c.Status(http.StatusNoContent)
}
